package com.tfswx.fljdmxyy.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelWriter;
import com.newbie.core.exception.BusinessException;
import com.tfswx.fljdmxyy.enums.BusinessCodeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.nio.file.Paths;
import java.util.*;

/**
 * excel工具
 *
 * @Author 陈文佳
 * @Date 2023/03/24
 */
@Slf4j
public class ExcelUtils {

    /**
     * 将数据写入Excel文件
     *
     * @param data-数据
     * @param file-Excel文件
     */
    public static void writeExcel(Iterable<?> data, File file) {
        writeExcel(data, file.getAbsolutePath());
    }

    /**
     * 将数据写入Excel文件
     *
     * @param data-数据
     * @param path-Excel文件路径
     */
    public static void writeExcel(Iterable<?> data, String path) {
        writeExcel(data, path, null);
    }

    /**
     * 将数据写入Excel文件
     *
     * @param data-数据
     * @param path-Excel文件路径
     * @param comparator-比较器，用于字段名的排序
     */
    public static void writeExcel(Iterable<?> data, String path, Comparator<String> comparator) {
        if (CollectionUtil.isEmpty(data)) {
            throw new BusinessException(BusinessCodeEnum.DCWSJ);
        }
        ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(Paths.get(path).toString());
        // 设置别名
        fillContent(data, comparator, writer);
        writer.close();
    }

    /**
     * 读取Excel文件中的数据（读取所有行，默认第一行做为标题，数据从第二行开始）
     *
     * @param file-Excel文件路径
     * @param headerAlias-标题行的别名Map
     * @param beanType-每行对应Bean的类型
     * @param <T>-Bean类型
     * @return 数据列表
     */
    public static <T> List<T> readExcel(File file, Map<String, String> headerAlias, Class<T> beanType) {
        return readExcel(file, headerAlias, 0, 1, beanType);
    }

    /**
     * 读取Excel文件中的数据
     *
     * @param file-Excel文件路径
     * @param headerAlias-标题行的别名Map
     * @param headerRowIndex-标题所在行，如果标题行在读取的内容行中间，这行做为数据将忽略，从0开始计数
     * @param startRowIndex–起始行（包含，从0开始计数）
     * @param beanType-每行对应Bean的类型
     * @param <T>-Bean类型
     * @return 数据列表
     */
    public static <T> List<T> readExcel(File file, Map<String, String> headerAlias, int headerRowIndex, int startRowIndex, Class<T> beanType) {
        try (ExcelReader reader = cn.hutool.poi.excel.ExcelUtil.getReader(new FileInputStream(file))) {
            reader.setHeaderAlias(headerAlias);
            return reader.read(headerRowIndex, startRowIndex, beanType);
        } catch (FileNotFoundException e) {
            log.error("文件未找到", e);
            throw new BusinessException(BusinessCodeEnum.WJWZD);
        }
    }

    private static void fillContent(Iterable<?> data, Comparator<String> comparator, ExcelWriter writer) {
        Iterator<?> iterator = data.iterator();
        Object next = iterator.next();
        int columnLen;
        if (next instanceof Map) {
            columnLen = ((Map) next).size();
        } else {
            handleBean(writer, next);
            columnLen = next.getClass().getDeclaredFields().length;
        }
        if (Objects.isNull(comparator)) {
            writer.write(data, true);
        } else {
            writer.write(data, comparator);
        }
        Sheet sheet = writer.getSheet();
        for (int i = 0; i < columnLen; i++) {
            sheet.autoSizeColumn(i);
            int width = Math.min(sheet.getColumnWidth(i) * 14 / 10, 65280);
            sheet.setColumnWidth(i, width);
        }
    }

    private static void handleBean(ExcelWriter writer, Object o) {
        for (Field declaredField : o.getClass().getDeclaredFields()) {
            ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
            if (Objects.isNull(annotation)) {
                log.info("{}-字段未使用“ApiModelProperty”注解", declaredField.getName());
            }
            if (Objects.nonNull(annotation)) {
                String value = annotation.value();
                writer.addHeaderAlias(declaredField.getName(), value);
            }
        }
        writer.setOnlyAlias(true);
    }
}
